package com.prd.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.prd.config.LoginInterceptor;
import com.prd.dto.AttendanceDTO;
import com.prd.dto.ClockOrNotDTO;
import com.prd.enums.WorkStatusEnum;
import com.prd.mapper.AttendanceMapper;
import com.prd.model.AttendanceDO;
import com.prd.model.AttendanceSettingDO;
import com.prd.model.LoginUser;
import com.prd.service.AttendanceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.prd.service.AttendanceSettingService;
import com.prd.service.FileService;
import com.prd.util.CommonUtil;
import com.prd.util.JsonData;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 *
 * @author lizhaoyi
 * @since 2023-10-03
 */
@Service
public class AttendanceServiceImpl extends ServiceImpl<AttendanceMapper, AttendanceDO> implements AttendanceService {

    @Autowired
    private AttendanceMapper attendanceMapper;

    @Autowired
    private FileService fileService;

    @Autowired
    private AttendanceSettingService attendanceSettingService;

    /**
     * 上班打卡
     * @param attendanceDto
     * @return
     */
    @Override
    public JsonData clockIn(AttendanceDTO attendanceDto) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        attendanceDto.setUserId(loginUser.getId());
        attendanceDto.setUserName(loginUser.getName());
        attendanceDto.setCreateTime(LocalDateTime.now());
        //设置考勤日期
        attendanceDto.setClockDate(LocalDate.now());
        //把上班时间设为当前
        LocalTime now = LocalTime.now();
        attendanceDto.setClockIn(now);
        attendanceDto.setClockOut(null);
        List<AttendanceSettingDO> settingDOS = attendanceSettingService.list();
        if (!CollectionUtils.isEmpty(settingDOS)) {
            AttendanceSettingDO attendanceSettingDO = settingDOS.get(0);
            if (now.isAfter(attendanceSettingDO.getRequestClockin().plusMinutes(attendanceSettingDO.getBeforeAndAfterTime())) ||
                    now.isBefore(attendanceSettingDO.getRequestClockin().minusMinutes(attendanceSettingDO.getBeforeAndAfterTime()))) {
                return JsonData.buildError("上班打卡时间点前后"+attendanceSettingDO.getBeforeAndAfterTime()+"分钟为无效打卡时间段");
            }
            LocalTime requestClockin = attendanceSettingDO.getRequestClockin();
            if (now.isBefore(requestClockin)) {
                //7:56打卡显示08:00:00
                attendanceDto.setClockIn(requestClockin);
            }
            //设置状态
            if(now.isAfter(requestClockin)){
                attendanceDto.setClockInStatus(WorkStatusEnum.BELATE.getCode());
            }else{
                attendanceDto.setClockInStatus(WorkStatusEnum.NORMAL.getCode());
            }
        }
        //禁止重复打卡
        //根据当日日期和用户id 查询当日打卡信息，在此基础做更新
        List<AttendanceDO> list = null;
        try {
            LambdaQueryWrapper<AttendanceDO> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(AttendanceDO::getClockDate, LocalDate.now());
            wrapper.eq(AttendanceDO::getUserId,loginUser.getId());
            list = attendanceMapper.selectList(wrapper);
            if (!list.isEmpty()){
                return JsonData.buildError("禁止重复打卡");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        AttendanceDO attendanceDO = CommonUtil.dtoTransfer(attendanceDto, AttendanceDO.class);

        attendanceMapper.insert(attendanceDO);
        attendanceDto.setId(attendanceDO.getId());
        return JsonData.buildSuccess(attendanceDO);
    }

    /**
     * 下班打卡
     * @param attendanceDto
     * @return
     */
    @Override
    public JsonData clockOut(AttendanceDTO attendanceDto) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        LambdaQueryWrapper<AttendanceDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AttendanceDO::getClockDate,LocalDate.now());
        wrapper.eq(AttendanceDO::getUserId,loginUser.getId());
        AttendanceDO attendanceDO = attendanceMapper.selectOne(wrapper);
        attendanceDO.setClockOutAddress(attendanceDto.getClockOutAddress());
        if (attendanceDO == null) {
            attendanceDto.setUserId(loginUser.getId());
            attendanceDto.setUserName(loginUser.getName());
            attendanceDto.setCreateTime(LocalDateTime.now());
            AttendanceDO attendance = CommonUtil.dtoTransfer(attendanceDto, AttendanceDO.class);
            int count = attendanceMapper.insert(CommonUtil.dtoTransfer(attendanceDto,AttendanceDO.class));
            if(count > 0){
                return JsonData.buildSuccess(attendance);
            }
            return JsonData.buildError("下班打卡异常");
        }
        if (attendanceDO.getClockOut() != null) {
            return JsonData.buildError("禁止重复打卡");
        }
        LocalTime now = LocalTime.now();
        //把下班时间设为当前
        attendanceDO.setClockOut(now);
        List<AttendanceSettingDO> settingDOS = attendanceSettingService.list();
        if (!CollectionUtils.isEmpty(settingDOS)) {
            AttendanceSettingDO attendanceSettingDO = settingDOS.get(0);
            if (now.isAfter(attendanceSettingDO.getRequestClockout().plusMinutes(attendanceSettingDO.getBeforeAndAfterTime())) ||
                    now.isBefore(attendanceSettingDO.getRequestClockout().minusMinutes(attendanceSettingDO.getBeforeAndAfterTime()))) {
                return JsonData.buildError("下班打卡时间点前后"+attendanceSettingDO.getBeforeAndAfterTime()+"分钟为无效打卡时间段");
            }
            LocalTime requestClockin = attendanceSettingDO.getRequestClockout();
            //设置状态
            if(now.isAfter(requestClockin)){
                attendanceDO.setClockOutStatus(WorkStatusEnum.LEAVE_EARLY.getCode());
            }else{
                attendanceDO.setClockOutStatus(WorkStatusEnum.NORMAL.getCode());
            }
        }
        int count = attendanceMapper.updateById(attendanceDO);
        if(count > 0){
            AttendanceDTO attendanceDTO = CommonUtil.dtoTransfer(attendanceDO, AttendanceDTO.class);
            attendanceDTO.setId(attendanceDO.getId());
            return JsonData.buildSuccess(attendanceDTO);
        }
        return JsonData.buildError("下班打卡异常");
    }


    /**
     * 上传图片
     * @param file
     * @return
     */
    @Override
    public JsonData uploadImg(MultipartFile file) {
        if (file == null) {
            return JsonData.buildError("图片不能为空");
        }
        String result = fileService.uploadImg(file);
        if (result == null) {
            return JsonData.buildError("上传图片异常");
        }

        return JsonData.buildSuccess(result);
    }


    /**
     * 确认上传
     * @param urls
     * @param remark
     * @param attendanceId
     * @return
     */
    @Override
    public JsonData confirmUpload(List<String> urls, String remark,String attendanceId) {

        LambdaQueryWrapper<AttendanceDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AttendanceDO::getId,attendanceId);
        wrapper.eq(AttendanceDO::getUserId,LoginInterceptor.threadLocal.get().getId());
        AttendanceDO attendanceDO = attendanceMapper.selectOne(wrapper);
        if (attendanceDO == null) {
            return JsonData.buildError("当前用户不存在打卡记录");
        }
        attendanceDO.setRemakes(remark);
        attendanceDO.setImgUrl(urls.toString());
        if(attendanceMapper.updateById(attendanceDO) > 0){
            return JsonData.buildSuccess(attendanceDO);
        }else {
            return JsonData.buildError("上传图片失败");
        }
    }

    /**
     * 是否已打上班卡
     * @return
     */
    @Override
    public JsonData isClockOrNot() {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        AttendanceDO attendanceDO = attendanceMapper.selectOne(new LambdaQueryWrapper<AttendanceDO>().eq(AttendanceDO::getUserId, loginUser.getId()));
        ClockOrNotDTO clockOrNotDTO = new ClockOrNotDTO();
        if (attendanceDO == null) {
            clockOrNotDTO.setIsClockIn(false);
            return JsonData.buildSuccess(clockOrNotDTO);
        }
        if (attendanceDO.getClockIn() == null && attendanceDO.getClockOut() != null) {
            clockOrNotDTO.setIsClockIn(false);
            clockOrNotDTO.setIsClockOut(true);
        }
        if (attendanceDO.getClockIn() != null &&attendanceDO.getClockOut() != null){
            clockOrNotDTO.setIsClockIn(true);
            clockOrNotDTO.setIsClockOut(true);
        }
        if (attendanceDO.getClockIn() != null &&attendanceDO.getClockOut() == null){
            clockOrNotDTO.setIsClockIn(true);
            clockOrNotDTO.setIsClockOut(false);
        }
        return JsonData.buildSuccess(clockOrNotDTO);
    }

    /**
     * 日统计
     * @param clockDate
     * @return
     */
    @Override
    public JsonData getAttendancesByOneDay(LocalDate clockDate) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        LambdaQueryWrapper<AttendanceDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AttendanceDO::getUserId,loginUser.getId());
        wrapper.eq(AttendanceDO::getClockDate,clockDate);
        List<AttendanceDO> attendanceDOList = attendanceMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(attendanceDOList)) {
            return JsonData.buildError("无考勤记录");
        }
        return getJsonData(attendanceDOList);
    }

    /**
     * 周统计
     * @param clockDate
     * @return
     */
    @Override
    public JsonData getWeekAttendances(LocalDate clockDate) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        LocalDate startTime = clockDate.with(DayOfWeek.MONDAY);
        LocalDate endTime = clockDate.with(DayOfWeek.SUNDAY);
        //获取本周的所有数据
        return getAttendanceDTOsByDate(loginUser.getId(), startTime, endTime);
    }

    /**
     * 月统计
     * @param clockMonth
     * @return
     */
    @Override
    public JsonData getMonthAttendances(String clockMonth) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        YearMonth yearMonth = YearMonth.parse(clockMonth, DateTimeFormatter.ofPattern("yyyy-MM"));
        LocalDate localDate = yearMonth.atEndOfMonth();
        LocalDate startTime = localDate.with(TemporalAdjusters.firstDayOfMonth());
        LocalDate endTime = localDate.with(TemporalAdjusters.lastDayOfMonth());
        //获取本月的所有数据
        return getAttendanceDTOsByDate(loginUser.getId(), startTime, endTime);
    }

    private JsonData getAttendanceDTOsByDate(Long userId, LocalDate startTime, LocalDate endTime) {
        QueryWrapper<AttendanceDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",userId);
        queryWrapper.between("clock_date",startTime,endTime);
        List<AttendanceDO> attendanceDOList = attendanceMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(attendanceDOList)) {
            return JsonData.buildError("暂无考勤记录");
        }
        return getJsonData(attendanceDOList);
    }

    private JsonData getJsonData(List<AttendanceDO> attendanceDOList) {
        List<AttendanceDTO> attendanceDTOS = CommonUtil.dtoListTransfer(attendanceDOList, AttendanceDTO.class);
        attendanceDTOS.stream().forEach(attendanceDTO -> {
            String urls = attendanceDTO.getImgUrl().substring(1, attendanceDTO.getImgUrl().length() - 1);
            attendanceDTO.setImgUrlList(Arrays.asList(urls));
        });
        return JsonData.buildSuccess(attendanceDTOS);
    }


}
